package com.tuuzed.hydrogen.internal;

import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.tuuzed.hydrogen.Model;

import java.util.Date;
import java.util.Iterator;
import java.util.List;


public final class ModelCursorProcessor<T extends Model> implements Iterator<T> {
    private static final String TAG = "ModelCursorProcessor";

    private Cursor cursor;
    private Class<T> clazz;
    private boolean hasNext;
    private List<Property> properties;

    public static <T extends Model> ModelCursorProcessor<T> create(@NonNull Cursor cursor, @NonNull Class<T> clazz) {
        return new ModelCursorProcessor<>(cursor, clazz);
    }

    private ModelCursorProcessor(Cursor cursor, Class<T> clazz) {
        this.cursor = cursor;
        this.clazz = clazz;
        hasNext = cursor.moveToFirst();
        properties = HydrogenContext.getDefault().getProperties(clazz);
    }

    @Override
    public boolean hasNext() {
        return hasNext;
    }

    @Override
    public T next() {
        T model = null;
        while (model == null) {
            try {
                model = processCursor(cursor, clazz);
            } catch (Exception e) {
                Log.d(TAG, "next: ", e);
            }
            hasNext = cursor.moveToNext();
            if (!hasNext()) return model;
        }
        return model;
    }

    @Override
    public void remove() {
        cursor.close();
    }

    @Nullable
    private T processCursor(Cursor cursor, Class<T> clazz)
            throws InstantiationException, IllegalAccessException {
        T model = clazz.newInstance();
        if (model != null) {
            model.setId(cursor.getLong(cursor.getColumnIndex("_id")));
            for (Property property : properties) {
                try {
                    setFieldValue(property, model, cursor);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return model;
    }

    private void setFieldValue(Property property, T model, Cursor cursor)
            throws IllegalAccessException, InstantiationException {
        Class<?> type = property.getJavaType();
        int columnIndex = cursor.getColumnIndex(property.getColumnName());
        if (columnIndex == -1) return;
        Object value = null;
        if (type == String.class) {
            value = cursor.getString(columnIndex);
        } else if (type == Date.class) {
            value = new Date(cursor.getLong(columnIndex));
        } else if (type == boolean.class || type == Boolean.class) {
            value = cursor.getInt(columnIndex) == 1;
        } else if (type == byte.class || type == Byte.class) {
            value = (byte) cursor.getInt(columnIndex);
        } else if (type == char.class || type == Character.class) {
            value = cursor.getString(columnIndex).charAt(0);
        } else if (type == short.class || type == Short.class) {
            value = cursor.getShort(columnIndex);
        } else if (type == int.class || type == Integer.class) {
            value = cursor.getInt(columnIndex);
        } else if (type == long.class || type == Long.class) {
            value = cursor.getLong(columnIndex);
        } else if (type == float.class || type == Float.class) {
            value = cursor.getFloat(columnIndex);
        } else if (type == double.class || type == Double.class) {
            value = cursor.getDouble(columnIndex);
        }
        property.setValue(model, value);
    }
}
